package wineshop.domain.market;

import java.io.Serializable;
import java.nio.ByteBuffer;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashSet;
import java.util.Set;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.OneToMany;
import javax.persistence.SequenceGenerator;
import javax.persistence.Version;

import wineshop.domain.general.Address;

/**
 * The persistent class for the customer database table.
 * 
 */
@Entity
public class Customer implements Serializable {
	private static final long serialVersionUID = 1L;

	@Id
	@SequenceGenerator(name = "cust_seq", sequenceName = "wineshop_seq", allocationSize = 1)
	@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "cust_seq")
	long id;

	@Version
	Integer version;

	private String name;

	private String surename;

	private String username;

	private String password;

	@OneToMany(mappedBy = "customer")
	private Set<Purchase> orders;

	@ManyToMany
	@JoinTable(name = "customercreditcard", joinColumns = @JoinColumn(name = "customer", referencedColumnName = "id"), inverseJoinColumns = @JoinColumn(name = "creditcard", referencedColumnName = "id"))
	private Set<Creditcard> creditCards;

	@ManyToMany
	@JoinTable(name = "addresscustomer", joinColumns = @JoinColumn(name = "customer", referencedColumnName = "id"), inverseJoinColumns = @JoinColumn(name = "address", referencedColumnName = "id"))
	private Set<Address> addresses;

	Customer() {
	}

	public Customer(String name, String surename, String username) {
		this.name = name;
		this.surename = surename;
		this.username = username;
		this.addresses = new HashSet<Address>();
		this.creditCards = new HashSet<Creditcard>();
	}

	public String getName() {
		return this.name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getPassword() {
		return this.password;
	}

	void setPassword(String password) {
		this.password = password;
	}

	public void setPassword(char[] password) {
		this.password = convertCharArraytoHashedString(password);
	}

	public String getSurename() {
		return this.surename;
	}

	public void setSurename(String surename) {
		this.surename = surename;
	}

	public String getUsername() {
		return this.username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public Set<Purchase> getOrders() {
		return this.orders;
	}

	public void setOrders(Set<Purchase> orders) {
		this.orders = orders;
	}

	public Set<Creditcard> getCreditCards() {
		return creditCards;
	}

	public void setCreditCards(Set<Creditcard> creditCards) {
		this.creditCards = creditCards;
	}

	public Set<Address> getAddresses() {
		return addresses;
	}

	public void setAddresses(Set<Address> addresses) {
		this.addresses = addresses;
	}

	public boolean hasPassword(char[] password) {
		return this.password.equals(convertCharArraytoHashedString(password));
	}

	private String convertCharArraytoHashedString(char[] chars) {
		byte[] ba = new byte[chars.length * 2];
		ByteBuffer.wrap(ba).asCharBuffer().put(chars);
		try {
			MessageDigest md = MessageDigest.getInstance("MD5");
			byte[] hashedPassword = md.digest(ba);
			return new String(hashedPassword);
		} catch (NoSuchAlgorithmException e) {
			throw new RuntimeException(
					"Cannot find MD5 digest on current platform");
		}
	}

	public void addAddress(Address address) {
		getAddresses().add(address);
	}

	public Purchase buy(Item wine, Creditcard card, Address addressDelivery) {
		return wine.getSeller().sell(wine, this, card, addressDelivery);
	}
}